﻿using Modbus.Messages;

namespace Modbus
{
	partial class ModbusClient
	{
		public bool[] ReadCoils(byte slaveAddress, int startingAddress, int quantity)
		{
			//
			// Input arguments validation.
			//

			Ensure.ArgumentNotEqualTo(SR.Argument_slaveAddress, slaveAddress, ModbusClient.BroadcastAddress);
			Ensure.ArgumentInRange(SR.Argument_startingAddress, startingAddress, MinDataAddress, MaxDataAddress);
			Ensure.ArgumentInRange(SR.Argument_quantity, quantity, ModbusSpecification.MinQuantity,
				ModbusSpecification.ReadCoilsMaxQuantity);

			//
			//
			//

			return this.ReadDiscretes(FunctionCodes.ReadCoils, slaveAddress, (ushort)(startingAddress),
				(ushort)(quantity));
		}

		public bool[] ReadDiscreteInputs(byte slaveAddress, int startingAddress, int quantity)
		{
			//
			// Input arguments validation.
			//

			Ensure.ArgumentNotEqualTo(SR.Argument_slaveAddress, slaveAddress, ModbusClient.BroadcastAddress);
			Ensure.ArgumentInRange(SR.Argument_startingAddress, startingAddress, MinDataAddress, MaxDataAddress);
			Ensure.ArgumentInRange(SR.Argument_quantity, quantity, ModbusSpecification.MinQuantity,
				ModbusSpecification.ReadDiscreteInputsMaxQuantity);

			return this.ReadDiscretes(FunctionCodes.ReadDiscreteInputs, slaveAddress, (ushort)(startingAddress),
				(ushort)(quantity));
		}

		private bool[] ReadDiscretes(byte functionCode, byte slaveAddress, ushort startingAddress, ushort quantity)
		{
			//
			// Internal state validation.
			//

			this.ThrowIfDisposed();

			//
			// Request creation.
			//

			StartingAddressQuantityMessage request = new StartingAddressQuantityMessage();

			request.FunctionCode = functionCode;
			request.StartingAddress = startingAddress;
			request.Quantity = quantity;

			//
			// Perform transaction.
			//

			var response = this.transport.Request<ReadDataResponse>(slaveAddress, request);

			//
			// Response validation.
			//

			int expectedByteCount = ((request.Quantity + 7) / 8);

			if (response.Data.Length != expectedByteCount)
			{
				throw new MismatchResponseException(SR.ModbusMessageField_ByteCount);
			}
			
			//
			// Prepare return value.
			//

			bool[] bits = DataUtility.DecodeDiscretes(request.Quantity, response.Data);

			return bits;
		}
	}
}
